package com.imooc.mmall.transactiona;

import com.imooc.mmall.dao.UserMapper;
import com.imooc.mmall.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.sql.SQLException;

/**
 * 注解方式——实现事物
 */
@Service
@Slf4j
public class CustomerServiceTxInAnnotation {

    @Autowired
    private UserMapper userMapper;


    /**
     * https://blog.csdn.net/u011410529/article/details/54287307
     *
     * REQUIRED：如果存在一个事务，则支持当前事务。如果没有事务则开启一个新的事务。
     * REPEATABLE_READ：这种事务隔离级别可以防止脏读，不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外，还保证了避免下面的情况产生(不可重复读)
     * readOnly：不允许只读 rollbackFor:回滚策略为Exception出现异常之后
     * TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 函数内捕获异常时需要来设置事务回滚状态
     * Spring Transactional一直是RD的事务神器，但是如果用不好，反会伤了自己。下面总结@Transactional经常遇到的几个场景:
     @Transactional 加于private方法, 无效
     @Transactional 加于未加入接口的public方法, 再通过普通接口方法调用, 无效
     @Transactional 加于接口方法, 无论下面调用的是private或public方法, 都有效
     @Transactional 加于接口方法后, 被本类普通接口方法直接调用, 无效
     @Transactional 加于接口方法后, 被本类普通接口方法通过接口调用, 有效
     @Transactional 加于接口方法后, 被它类的接口方法调用, 有效
     @Transactional 加于接口方法后, 被它类的私有方法调用后, 有效
     */
    @Transactional(
            isolation = Isolation.REPEATABLE_READ
            , propagation = Propagation.REQUIRED
            ,readOnly = false
            , rollbackFor = Exception.class
    )
    public void create(User user) throws SQLException {
        createUser(user);
        LocalTranJdbcApplication.createError();
    }


    public void createUser(User user){
        userMapper.insert(user);
    }

}
